package dataset;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import triples.Triple;
import triples.TriplesProcessor;
import yagoMarried.IndexTACWriter;

public class Dataset {
	public ArrayList<DataEntry> entries;
	public Dataset(ArrayList<DataEntry> entries){
		this.entries = entries;
	}
	
	public void toText(String dir){
		
		try {
			File dataFile = new File(dir);
			if(!dataFile.exists()){
				dataFile.createNewFile();
			}
			BufferedWriter output = new BufferedWriter( new FileWriter(dataFile) );
			StringBuffer sb = new StringBuffer();
			for( DataEntry e: entries ){
				sb.append("SON_SEN:"+e.getSentence()+"\n");
				sb.append("NER_SEN:"+e.getNew_sentence()+"\n");
				sb.append("ORI_SEN:"+e.getOri_sentence()+"\n");
				sb.append(("relation:"+e.relation+"\n"));
				sb.append("Relations:");
				for( int i =0; i<e.dates.size();i++){
					sb.append((i+1)+"[DATE:"+e.dates.get(i)+",REL:"+e.related.get(i)+"]");
					sb.append("\t");
				}
				sb.append("\n");
				sb.append("*****************\n");
			}
			
			output.write(sb.toString());
			output.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//related only has value 1 or  zero
	public Dataset binaryDataSet(){
		ArrayList<DataEntry> newentries = new ArrayList<DataEntry> ();
		for( DataEntry e: this.entries){
			ArrayList<String> newRelated = new ArrayList<String>();
			for( String r: e.related){
				if( r.equals("No event")||r.equals("no tlink")||r.equals("No")||r.startsWith("e-e:AFTER")||r.startsWith("e-e:BEFORE")||r.equals("AFTER")||r.equals("BEFORE") ){
					newRelated.add("NON");
				}else {
					newRelated.add("REL");
				}
			}
			DataEntry ne = new DataEntry(e.getTriple(),e.relation,e.dates,newRelated);
			newentries.add(ne);
		}
		
		Dataset newset = new Dataset(newentries);
		return newset;
	}
	
	//query dataset
	public Dataset queryDataSet(){
		ArrayList<DataEntry> newentries = new ArrayList<DataEntry> ();
		for( DataEntry e: this.entries){
			ArrayList<String> newRelated = new ArrayList<String>();
			for( String r: e.related){
				newRelated.add("UNKOWN");
			}
			DataEntry ne = new DataEntry(e.getTriple(),e.relation,e.dates,newRelated);
			newentries.add(ne);
		}
		
		Dataset newset = new Dataset(newentries);
		return newset;
	}
	
	//public evaluate precision
	public float precision(Dataset resultset){
		float total = 0;
		float correct = 0;
		ArrayList<DataEntry> true_entries = this.entries;
		ArrayList<DataEntry> res_entries = resultset.entries;
		for( int i=0;i<true_entries.size();i++){
			DataEntry true_e = true_entries.get(i);
			DataEntry res_e = res_entries.get(i);
			ArrayList<String> true_rs = true_e.related;
			ArrayList<String> res_rs = res_e.related;
			for( int j=0;j<true_rs.size();j++){
				total++;
				String true_r = true_rs.get(j);
				String res_r = res_rs.get(j);
				if( true_r.equals(res_r)){
					correct++;
				}
			}
		}
		
		System.out.println("correct:"+correct+" total:"+total+" precision:"+(correct/total));
		return correct/total;
		
	}
	
	public float recall(Dataset resultset){
		float total = 0;
		float correct = 0;
		ArrayList<DataEntry> true_entries = this.entries;
		ArrayList<DataEntry> res_entries = resultset.entries;
		for( int i=0;i<true_entries.size();i++){
			DataEntry true_e = true_entries.get(i);
			DataEntry res_e = res_entries.get(i);
			ArrayList<String> true_rs = true_e.related;
			ArrayList<String> res_rs = res_e.related;
			for( int j=0;j<true_rs.size();j++){
				
				String true_r = true_rs.get(j);
				String res_r = res_rs.get(j);
				if(true_r.equals("REL")){
					total++;
					if( true_r.equals(res_r)){
						correct++;
					}
				}
			}
		}
		
		System.out.println("correct:"+correct+" total:"+total+" recall:"+(correct/total));
		return correct/total;
	}
	public static File[] getAllFiles(String dir){
		File directory = new File(dir);
        File[] files = directory.listFiles();
    //    System.out.println(files.length);
        for (int i = 0; i < files.length; i++) {
        //	System.out.println(i + ":" + files[i].getName() + ";;;"+ files[i].getAbsolutePath());
           //files[i].renameTo(new File(dir + i + files[i].getName()));
   
           
           //System.out.println(files[i].getName());
       }
       return files;
	}
	public static Dataset dataFromDir(String fileDir){
		File[] files = getAllFiles(fileDir);
		ArrayList<DataEntry> list = new ArrayList<DataEntry>();
		for(int i=0; i<files.length;i++){
			
			//System.out.println(i+"/"+files.length);
			String abspath = files[i].getAbsolutePath();
			Dataset ds = dataFromText(abspath);
			list.addAll(ds.entries);
		}
		return new Dataset(list);
	}
	public static Dataset dataFromText(String dir){
		try {
			String text = TriplesProcessor.getFileContents(dir);
			String[] entries_text = text.split("\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\\*\n");
			ArrayList<DataEntry> entries = new ArrayList<DataEntry>();
			for( String entry_text:entries_text){
			//	System.out.println(entry_text);
			//	System.out.println("---------------------");
				if(entry_text.equals("")){
					continue;
				}
				DataEntry de = entryFromString(entry_text);
				entries.add(de);
			}
			return new Dataset(entries);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	public static DataEntry entryFromString(String entryString){
		String[] lines = entryString.split("\n");
		//line[0] sen, line[1] new sen,line[2] ,line[3] relation
		Triple tri = new Triple(lines[0].substring(8),lines[1].substring(8),lines[2].substring(8),false);
		String relation = lines[3].substring(9);
		
		ArrayList<String> dates = new ArrayList<String>();
		ArrayList<String> rels = new ArrayList<String>();
		
		String p="\\[DATE:(.*?),REL:(.*?)\\]";
		Pattern pattern = Pattern.compile(p);
		Matcher matcher = pattern.matcher(lines[4].substring(9));
		while( matcher.find()){
			String date = matcher.group(1);
			String rel  = matcher.group(2);
			dates.add(date);
			rels.add(rel);
		}
		
		return new DataEntry(tri,relation,dates,rels);
		
	}
	// acturally this is the actual precision:
		//among all the relations recognized as related, how many of them are actually related
		public float actual_precision(Dataset resultset){
			float total_identified = 0;
			float correct = 0;
			ArrayList<DataEntry> true_entries = this.entries;
			ArrayList<DataEntry> res_entries = resultset.entries;
			for( int i=0;i<true_entries.size();i++){
				DataEntry true_e = true_entries.get(i);
				DataEntry res_e = res_entries.get(i);
				ArrayList<String> true_rs = true_e.related;
				ArrayList<String> res_rs = res_e.related;
				for( int j=0;j<true_rs.size();j++){
					
					String true_r = true_rs.get(j);
					String res_r = res_rs.get(j);
					if(res_r.equals("REL")){
						//System.out.println("res_r:"+res_r+",true_r:"+true_r);
						
						total_identified++;
						if( true_r.equals(res_r)){
							correct++;
							//System.out.println("correctly recognized");
						}else{
							//System.out.println("incorrectly recognized");
						}
					}
				}
			}
			
			System.out.println("correct identified as REL:"+correct+" total identified as realted:"+total_identified+" actual precision:"+(correct/total_identified));
			return correct/total_identified;
			
		}
		
		public void false_positives(Dataset resultset, String dir){
			int fp=0;
			File dataFile = new File(dir);
			if(!dataFile.exists()){
				try {
					dataFile.createNewFile();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			try {
				BufferedWriter	 output = new BufferedWriter( new FileWriter(dataFile) );
			
			
			StringBuffer sb = new StringBuffer();
			sb.append("####################FALSE NEGATIVES###################");
			
			float total_identified = 0;
			float correct = 0;
			ArrayList<DataEntry> true_entries = this.entries;
			ArrayList<DataEntry> res_entries = resultset.entries;
			for( int i=0;i<true_entries.size();i++){
				DataEntry true_e = true_entries.get(i);
				DataEntry res_e = res_entries.get(i);
				ArrayList<String> true_rs = true_e.related;
				ArrayList<String> res_rs = res_e.related;
				for( int j=0;j<true_rs.size();j++){
					
					String true_r = true_rs.get(j);
					String res_r = res_rs.get(j);
					if(res_r.equals("REL")){
					//	System.out.println("res_r:"+res_r+",true_r:"+true_r);
						
						total_identified++;
						if( true_r.equals(res_r)){
							correct++;
						//	System.out.println("correctly recognized");
							
							
						}else{
							fp++;
						//	System.out.println("incorrectly recognized");
							sb.append("True Entry:\n");
							sb.append(true_e.toString());
							sb.append("<-------------->");
							sb.append("Result Entry:\n");
							sb.append(res_e.toString());
							sb.append("\n");
							sb.append("@@@@@@@@@@@@@");
						}
					}
				}
			}
			
			output.write(sb.toString());
			output.close();
			System.out.println("false postives:"+fp);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
			
			//System.out.println("correct identified as REL:"+correct+" total identified as realted:"+total_identified+" actual precision:"+(correct/total_identified));
			//return correct/total_identified;
		}
		
		public void false_negatives(Dataset resultset, String dir){
			
			int fn = 0;
			File dataFile = new File(dir);
			if(!dataFile.exists()){
				try {
					dataFile.createNewFile();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			try {
			BufferedWriter	 output = new BufferedWriter( new FileWriter(dataFile) );
			
			StringBuffer sb = new StringBuffer();
			
			sb.append("####################FALSE NEGATIVES###################");
			ArrayList<DataEntry> true_entries = this.entries;
			ArrayList<DataEntry> res_entries = resultset.entries;
			for( int i=0;i<true_entries.size();i++){
				DataEntry true_e = true_entries.get(i);
				DataEntry res_e = res_entries.get(i);
				ArrayList<String> true_rs = true_e.related;
				ArrayList<String> res_rs = res_e.related;
				for( int j=0;j<true_rs.size();j++){
					
					String true_r = true_rs.get(j);
					String res_r = res_rs.get(j);
					if(res_r.equals("NON")){
						
						if( !true_r.equals(res_r)){
							fn++;
							
							sb.append("True Entry:\n");
							sb.append(true_e.toString());
							sb.append("<-------------->");
							sb.append("Result Entry:\n");
							sb.append(res_e.toString());
							sb.append("\n");
							sb.append("@@@@@@@@@@@@@");
						}
					}
				}
			}
			System.out.println("false negatives:"+fn);
			output.write(sb.toString());
			output.close();
		}
			catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
}
